﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web.Hosting;
using System.Collections.Specialized;
using MyForum.Business;
using MyForum.Business.Controllers;
using System.Configuration.Provider;

namespace MyForum.Providers
{
    public class MyForumRoleProvider : RoleProvider
    {
        private string m_applicationName;

        public override void Initialize(string name, NameValueCollection config)
        {
            #region Validation
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            #endregion

            if (name == null || name.Length == 0)
            {
                name = "MyForumRoleProvider";
            }

            if (String.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "MyForum role provider");
            }

            m_applicationName = ProviderHelper.GetConfigValue(config["applicationName"], HostingEnvironment.ApplicationVirtualPath);

            base.Initialize(name, config);
        }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            #region Validation
            if (usernames == null)
            {
                throw new ArgumentNullException("usernames");
            }

            if (roleNames == null)
            {
                throw new ArgumentNullException("roleNames");
            }
            #endregion

            foreach (string username in usernames)
            {
                User user = UserController.GetUser(username);

                if (user == null)
                {
                    throw new MembershipPasswordException("The supplied user name is not found.");
                }

                foreach (string roleName in roleNames)
                {
                    if (!RoleExists(roleName))
                    {
                        throw new ProviderException("Role name not found.");
                    }

                    if (IsUserInRole(username, roleName))
                    {
                        throw new ProviderException("User is already in role.");
                    }

                    Role role = RoleController.GetRole(roleName);

                    if (role == null)
                    {
                        throw new MembershipPasswordException("Role name not found.");
                    }

                    RoleController.AddUserToRole(user, role);
                }
            }
        }

        public override string ApplicationName
        {
            get { return m_applicationName; }
            set { m_applicationName = value; }
        }

        public override void CreateRole(string roleName)
        {
            #region Validation
            if (String.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }
            #endregion

            if (RoleExists(roleName))
            {
                throw new ProviderException("Role name already exists.");
            }

            RoleController.CreateRole(roleName);
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            #region Validation
            if (String.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }
            #endregion

            if (!RoleExists(roleName))
            {
                throw new ProviderException("Role does not exist.");
            }

            if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0)
            {
                throw new ProviderException("Cannot delete a populated role.");
            }

            bool result = RoleController.DeleteRole(roleName);

            return result;
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            #region Validation
            if (String.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }

            if (String.IsNullOrEmpty(usernameToMatch))
            {
                throw new ArgumentNullException("usernameToMatch");
            }
            #endregion

            List<string> result = new List<string>();
            IQueryable<User> users = RoleController.FindUsersInRole(roleName, usernameToMatch);

            foreach (User user in users)
            {
                result.Add(user.Username);
            }

            return result.ToArray();
        }

        public override string[] GetAllRoles()
        {
            List<string> result = new List<string>();
            IQueryable<Role> roles = RoleController.SelectAll();

            foreach (Role role in roles)
            {
                result.Add(role.Rolename);
            }

            return result.ToArray();
        }

        public override string[] GetRolesForUser(string username)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }
            #endregion

            User user = UserController.GetUser(username);

            if (user == null)
            {
                throw new MembershipPasswordException("The supplied user name is not found.");
            }

            List<string> result = new List<string>();

            foreach (UserInRole membership in user.UserInRoles)
            {
                result.Add(membership.Role.Rolename);
            }

            return result.ToArray();
        }

        public override string[] GetUsersInRole(string roleName)
        {
            #region Validation
            if (String.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }
            #endregion

            Role role = RoleController.GetRole(roleName);

            if (role == null)
            {
                throw new MembershipPasswordException("Role does not exist.");
            }

            List<string> result = new List<string>();

            foreach (UserInRole membership in role.UsersInRole)
            {
                result.Add(membership.User.Username);
            }

            return result.ToArray();
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            #region Validation
            if (String.IsNullOrEmpty(username))
            {
                throw new ArgumentNullException("username");
            }

            if (String.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }
            #endregion

            bool result = RoleController.IsUserInRole(username, roleName);

            return result;
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            #region Validation
            if (usernames == null)
            {
                throw new ArgumentNullException("usernames");
            }

            if (roleNames == null)
            {
                throw new ArgumentNullException("roleNames");
            }
            #endregion

            foreach (string username in usernames)
            {
                User user = UserController.GetUser(username);

                if (user == null)
                {
                    throw new MembershipPasswordException("The supplied user name is not found.");
                }

                foreach (string roleName in roleNames)
                {
                    if (!RoleExists(roleName))
                    {
                        throw new ProviderException("Role name not found.");
                    }

                    if (!IsUserInRole(username, roleName))
                    {
                        throw new ProviderException("User is not in role.");
                    }

                    Role role = RoleController.GetRole(roleName);

                    if (role == null)
                    {
                        throw new MembershipPasswordException("Role name not found.");
                    }

                    RoleController.RemoveUserFromRole(user, role);
                }
            }
        }

        public override bool RoleExists(string roleName)
        {
            #region Validation
            if (String.IsNullOrEmpty(roleName))
            {
                throw new ArgumentNullException("roleName");
            }
            #endregion

            Role role = RoleController.GetRole(roleName);

            return role != null;
        }
    }
}
